// wtkevent.hpp
//

#ifndef _WTKEVENT_HPP
#define _WTKEVENT_HPP

#include "wtk/wtkbase.hpp"

namespace wtk
{
  class Display;
  class Widget;


  
  // EventType
  //
  enum class EventType : unsigned int
    {
      KeyUp,
      KeyDown,
      MouseMotion,
      MouseButtonUp,
      MouseButtonDown,
      MouseWheel,
    };



  // EventMaskShift
  //
  enum class EventMaskShift : size_t
    {
      Keyboard,
      MouseMotion,
      MouseButton,
      MouseWheel,
    };


  
  // EventMaskBit
  //
  enum class EventMaskBit : unsigned int
    {
      Keyboard = 1 << WTK_ENUM_VALUE(EventMaskShift::Keyboard),
      MouseMotion = 1 << WTK_ENUM_VALUE(EventMaskShift::MouseMotion),
      MouseButton = 1 << WTK_ENUM_VALUE(EventMaskShift::MouseButton),
    };



  // EVENT_TYPE_MASK_BIT
  //
  static inline constexpr EventMaskBit EVENT_TYPE_MASK_BIT[] =
    {
      [WTK_ENUM_VALUE(EventType::KeyUp)]   = EventMaskBit::Keyboard,
      [WTK_ENUM_VALUE(EventType::KeyDown)] = EventMaskBit::Keyboard,
      [WTK_ENUM_VALUE(EventType::MouseMotion)] = EventMaskBit::MouseMotion,
      [WTK_ENUM_VALUE(EventType::MouseButtonUp)] = EventMaskBit::MouseButton,
      [WTK_ENUM_VALUE(EventType::MouseButtonDown)] = EventMaskBit::MouseButton,
      [WTK_ENUM_VALUE(EventType::MouseWheel)] = EventMaskBit::MouseButton,
    };



  // _WTK_EVENT_HEADER
  //
#define _WTK_EVENT_HEADER                       \
  EventType type;                               \
  Display *display;                             \
  Widget *widget


  
  // EventAny
  //
  struct WTK_API EventAny
  {
    _WTK_EVENT_HEADER;
  };



  // EventKeyboard
  //
  struct WTK_API EventKeyboard
  {
    _WTK_EVENT_HEADER;

    unsigned int scancode;
    unsigned int keycode;
    unsigned int modifiers;

    void init ( EventType type,
                Display *display,
                Widget *widget,
                int scancode,
                int keycode,
                int modifiers )
    {
      WTK_ASSERT(type == EventType::KeyUp ||
                 type == EventType::KeyDown);

      this->type = type;
      this->display = display;
      this->widget = widget;
      this->scancode = scancode;
      this->keycode = keycode;
      this->modifiers = modifiers;
    }
  };



  // EventMouseMotion
  //
  struct WTK_API EventMouseMotion
  {
    _WTK_EVENT_HEADER;

    int state;
    int x;
    int y;
    int xrel;
    int yrel;

    void init ( EventType type,
                Display *display,
                Widget *widget,
                int state,
                int x,
                int y,
                int xrel,
                int yrel )
    {
      WTK_ASSERT(type == EventType::MouseMotion);

      this->type = type;
      this->display = display;
      this->widget = widget;
      this->state = state;
      this->x = x;
      this->y = y;
      this->xrel = xrel;
      this->yrel = yrel;
    }
  };



  // EventMouseButton
  //
  struct WTK_API EventMouseButton
  {
    _WTK_EVENT_HEADER;

    int button;
    int state;
    int clicks;
    int x;
    int y;

    void init ( EventType type,
                Display *display,
                Widget *widget,
                int button,
                int state,
                int clicks,
                int x,
                int y )
    {
      WTK_ASSERT(type == EventType::MouseButtonDown
                 || type == EventType::MouseButtonUp);

      this->type = type;
      this->display = display;
      this->widget = widget;
      this->button = button;
      this->state = state;
      this->clicks = clicks;
      this->x = x;
      this->y = y;
    }
  };



  // EventMouseWheel
  //
  struct WTK_API EventMouseWheel
  {
    _WTK_EVENT_HEADER;

    int wx;
    int wy;

    void init ( EventType type,
                Display *display,
                Widget *widget,
                int wx,
                int wy )
    {
      WTK_ASSERT(type == EventType::MouseWheel);

      this->type = type;
      this->display = display;
      this->widget = widget;
      this->wx = wx;
      this->wy = wy;
    }
  };



  // Event
  //
  union Event
  {
    EventType type;
    EventAny any;
    EventKeyboard keyboard;
    EventMouseMotion motion;
    EventMouseButton button;
    EventMouseWheel wheel;
  };



  // IEventListener
  //
  class WTK_API IEventListener
  {
  public:
    virtual void event ( const Event &event ) = 0;
  };
}

#endif
